package com.apobates.forum.core.service;

import com.apobates.forum.core.ImageIOMeta;
import com.apobates.forum.core.TagRelateTopic;
import com.apobates.forum.core.entity.Board;
import com.apobates.forum.core.entity.ForumEntityStatusEnum;
import com.apobates.forum.core.entity.Topic;
import com.apobates.forum.core.entity.TopicConfig;
import com.apobates.forum.core.entity.proxy.TopicReplica;
import com.apobates.forum.core.plug.AbstractPlugTopic;
import com.apobates.forum.event.elderly.ActionEventCulpritor;
import com.apobates.forum.event.elderly.ForumActionEnum;
import com.apobates.forum.utils.lang.ReplicableException;
import com.apobates.forum.utils.persistence.Page;
import com.apobates.forum.utils.persistence.Pageable;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.TreeMap;
import java.util.stream.Stream;
import com.apobates.forum.core.plug.PlugTopic;

/**
 * 话题的业务接口
 *
 * @author xiaofanku
 * @since 20200510
 */
public interface TopicService {
    /**
     * 发布[普通]话题, 操作成功后会发送通知(TopicPublishEvent)
     *
     * @param volumesId 版块组(卷)ID
     * @param boardId 版块ID
     * @param title 话题主题
     * @param content 话题内容
     * @param imageIO 图片存储信息
     * @param culpritor 操作的肇事信息
     * @return
     */
    long create(int volumesId, long boardId, String title, String content, ImageIOMeta imageIO, ActionEventCulpritor culpritor);
    
    /**
     * [前台]发布指定类型的话题, 操作成功后会发送通知(TopicPublishEvent)
     *
     * @param volumesId 版块组(卷)ID
     * @param boardId 版块ID
     * @param categoryId 话题类型ID,等于0等同于普通
     * @param title 话题主题
     * @param content 话题内容
     * @param imageIO 图片存储信息
     * @param culpritor 操作的肇事信息
     * @return
     */
    long create(int volumesId, long boardId, int categoryId, String title, String content, ImageIOMeta imageIO, ActionEventCulpritor culpritor);
    
    /**
     * [后台]发布指定类型的话题, 操作成功后会发送通知(TopicPublishEvent)
     *
     * @param volumesId 版块组(卷)ID
     * @param boardId 版块ID
     * @param categoryName 话题类型名称
     * @param categoryValue 话题类型参数值
     * @param title 话题主题
     * @param content 话题内容
     * @param keywords 话题标签称数组
     * @param imageIO 图片存储信息
     * @param culpritor 操作的肇事信息
     * @return
     */
    long create(int volumesId, long boardId, String categoryName, String categoryValue, String title, String content, String[] keywords, ImageIOMeta imageIO, ActionEventCulpritor culpritor);
    
    /**
     * 发布文章, 操作成功后会发送通知(TopicPublishEvent)
     *
     * @since 20200427
     * @param sectionId 栏目ID
     * @param termId 子栏目ID
     * @param title 文章标题
     * @param content 文章内容
     * @param imageIO 图片存储信息
     * @param culpritor 操作的肇事信息
     * @return
     */
    long createTermArticle(int sectionId, long termId, String title, String content, ImageIOMeta imageIO, ActionEventCulpritor culpritor);
    
    /**
     * 保存插件类话题, 适用于反馈,举报话题(,回复)
     * 不提取标签,不创建话题像册
     * 操作成功后会发送通知(PlugTopicPublishEvent)
     *
     * @param topicBuildPlug 方法不会执行清理工作
     * @return
     */
    Optional<TopicReplica> plug(AbstractPlugTopic topicBuildPlug);
    
    /**
     * 保存插件类话题
     * 不提取标签,不创建话题像册
     * 操作成功后会发送通知(PlugTopicPublishEvent)
     * @param topicBuildPlug 方法不会执行清理工作
     * @param action 动作
     * @param culpritor 操作的肇事信息
     * @return 
     */
    Optional<TopicReplica> plug(PlugTopic topicBuildPlug, ForumActionEnum action, ActionEventCulpritor culpritor);
    
    /**
     * 置顶话题
     *
     * @param id 话题ID
     * @param culpritor 操作的肇事信息
     * @return
     */
    Optional<Boolean> editTop(long id, ActionEventCulpritor culpritor);
    
    /**
     * 取消话题的置顶
     *
     * @param id 话题ID
     * @param culpritor 操作的肇事信息
     * @return
     */
    Optional<Boolean> removeTop(long id, ActionEventCulpritor culpritor);
    
    /**
     * 加精话题
     *
     * @param id 话题ID
     * @param culpritor 操作的肇事信息
     * @return
     */
    Optional<Boolean> editGoods(long id, ActionEventCulpritor culpritor);
    
    /**
     * 取消话题的加精
     *
     * @param id 话题ID
     * @param culpritor 操作的肇事信息
     * @return
     */
    Optional<Boolean> removeGoods(long id, ActionEventCulpritor culpritor);
    
    /**
     * 话题点赞
     *
     * @param id 话题ID
     * @param culpritor 操作的肇事信息
     * @return
     */
    Optional<Boolean> like(long id, ActionEventCulpritor culpritor)throws IllegalStateException;
    
    /**
     * 取消会员的点赞
     *
     * @param id 话题ID
     * @param culpritor 操作的肇事信息
     * @return
     */
    Optional<Boolean> removeLike(long id, ActionEventCulpritor culpritor)throws IllegalStateException;
    
    /**
     * 锁定话题
     *
     * @param id 话题ID
     * @param culpritor 操作的肇事信息
     * @return
     */
    Optional<Boolean> lock(long id, ActionEventCulpritor culpritor);
    
    /**
     * 解锁锁定的话题
     *
     * @param id 话题ID
     * @param culpritor 操作的肇事信息
     * @return
     */
    Optional<Boolean> releaseLock(long id, ActionEventCulpritor culpritor);
    
    /**
     * 删除话题
     *
     * @param id 话题ID
     * @param culpritor 操作的肇事信息
     * @return
     */
    Optional<Boolean> remove(long id, ActionEventCulpritor culpritor);
    
    /**
     * 删除子栏目的文章
     *
     * @since 20200427
     * @param id 子栏目的文章ID
     * @param termId 子栏目的ID
     * @param culpritor 操作的肇事信息
     * @return
     */
    Optional<Boolean> removeTermArticle(long id, long termId, ActionEventCulpritor culpritor);
    
    /**
     * 收藏话题
     *
     * @param id 话题ID
     * @param culpritor 操作的肇事信息
     * @return
     */
    Optional<Boolean> favorite(long id, ActionEventCulpritor culpritor)throws IllegalStateException;
    
    /**
     * 取消会员的收藏
     *
     * @param id 话题ID
     * @param culpritor 操作的肇事信息
     * @return
     */
    Optional<Boolean> removeFavorite(long id, ActionEventCulpritor culpritor)throws IllegalStateException;
    
    /**
     * 是否可以点赞, 可以返回true
     *
     * @param id 话题ID
     * @param memberId 会员ID
     * @return
     */
    boolean isLiked(long id, long memberId);
    
    /**
     * 是否可以收藏, 可以返回true
     *
     * @param id 话题ID
     * @param memberId 会员ID
     * @return
     */
    boolean isFavorited(long id, long memberId);
    
    /**
     * 浏览话题
     *
     * @param id 话题ID
     * @param culpritor 操作的肇事信息
     * @return
     */
    Optional<Boolean> browse(long id, ActionEventCulpritor culpritor);
    
    /**
     * 移动话题, 操作成功后会发送通知(TopicMoveEvent)
     *
     * @param id 话题ID
     * @param boardId 现在的版块ID
     * @param targetBoardId 目标版块ID
     * @param culpritor 操作的肇事信息
     * @return
     */
    Optional<Boolean> move(long id, long boardId, long targetBoardId, ActionEventCulpritor culpritor)throws ReplicableException,IllegalArgumentException,IllegalStateException;
    
    /**
     * 执行编辑话题配置检查,适用于前端执行,会进行话题作者,版主身份检测
     *
     * @param id 话题ID
     * @param updateConfig 更新的话题配置实例
     * @param configId 话题配置ID
     * @param culpritor 操作的肇事信息
     * @return
     */
    Optional<Boolean> editTopicConfig(long id, TopicConfig updateConfig, long configId, ActionEventCulpritor culpritor)throws IllegalArgumentException;
    
    /**
     * 编辑话题
     *
     * @param id 话题ID
     * @param title 主题
     * @param content 内容
     * @param keywords 关键词
     * @param imageIO 图片存储信息
     * @param culpritor 操作的肇事信息
     * @return
     */
    Optional<Boolean> edit(long id, String title, String content, String[] keywords, ImageIOMeta imageIO, ActionEventCulpritor culpritor)throws IllegalArgumentException,IllegalStateException;
    
    /**
     * 编辑文章
     *
     * @since 20200427
     * @param articleId 文章ID
     * @param title 主题
     * @param content 内容
     * @param imageIO 图片存储信息
     * @param culpritor 操作的肇事信息
     * @return
     */
    Optional<Boolean> editTermArticle(long articleId, String title, String content, ImageIOMeta imageIO, ActionEventCulpritor culpritor)throws IllegalArgumentException,IllegalStateException;
    
    /**
     * 查看指定版块下的所有话题,不包括删除,置顶;包括加精,普通;级联加载话题统计
     *
     * @param boardId 版块ID
     * @param pageable 分页请求参数
     * @return
     */
    Page<TopicReplica> getAll(long boardId, Pageable pageable);
    
    /**
     * 查看指定版块下的指定类型的话题,不包括删除,置顶;包括加精,普通;级联加载话题统计
     *
     * @param boardId 版块ID
     * @param categoryValue 话题类型的Key(Topic.topicCategoryValue = TopicCategory.value)
     * @param pageable 分页请求参数
     * @return
     */
    Page<TopicReplica> getAll(long boardId, String categoryValue, Pageable pageable);
    
    /**
     * 查看指定会员发布的所有话题,会级联加载话题统计
     *
     * @param memberId 会员ID
     * @param pageable 分页请求参数
     * @return
     */
    Page<TopicReplica> getAllForMember(long memberId, Pageable pageable);
    
    /**
     * 统计会员发布话题的总数
     *
     * @param memberId 会员ID
     * @return
     */
    long countAllForMember(long memberId);
    
    /**
     * 查看会员回复的话题,话题的作者不是该会员(不包含自已发的),会级联加载话题的统计
     *
     * @param memberId 会员ID
     * @param pageable 分页请求参数
     * @return
     */
    Page<TopicReplica> getAllForMemberReply(long memberId, Pageable pageable);
    
    /**
     * 统计会员回复的总数
     *
     * @param memberId 会员ID
     * @return
     */
    long countAllForMemberReply(long memberId);
    
    /**
     * 查看指定子栏目下的所有文章
     *
     * @since 20200427
     * @param termId 子栏目ID
     * @param pageable 分页请求参数
     * @return
     */
    Page<Topic> getTermArticle(long termId, Pageable pageable);
    
    /**
     * 根据标签查看相关的话题
     *
     * @param tagNames 标签名称
     * @param pageable 分页请求参数
     * @return
     */
    Page<Topic> getAllForTag(List<String> tagNames, Pageable pageable);
    
    /**
     * 查看指定日期范围内的话题,不包括删除的,不包含举报和反馈类型.方法会级联加载版块,话题统计
     * 
     * @param start 开始日期
     * @param finish 结束日期
     * @param pageable 分页请求参数
     * @return 
     */
    Page<TopicReplica> getAllRelateContent(LocalDateTime start, LocalDateTime finish, Pageable pageable);
    
    /**
     * 查看指定版块最近的话题,不包括删除,置顶;包括加精,普通;以rankingDateTime倒序 服务于RSS
     *
     * @param boardId 版块ID
     * @param size 显示的数量
     * @return
     */
    Stream<Topic> getRecentForBoard(long boardId, int size);
    
    /**
     * 查看指定版块最近的话题, 忽略状态;以entryDateTime倒序 服务于策略检查
     *
     * @param boardId 版块ID
     * @param size 显示的数量
     * @return
     */
    Stream<Topic> getRecentForBoardIgnoreStatus(long boardId, int size);
    
    /**
     * 指定版块置顶的话题,不包括删除;会级联加载话题统计
     *
     * @param boardId 版块ID
     * @return
     */
    Stream<TopicReplica> getTopForBoard(long boardId);
    
    /**
     * 查看指定会员最近发布的话题,级联加载版块
     *
     * @param memberId 会员ID
     * @param size 显示的数量
     * @return
     */
    Stream<TopicReplica> getRecentForMember(long memberId, int size);
    
    /**
     * 查看指定会员最近回复的话题,话题的作者不是该会员(不包含自已发的),级联加载版块
     *
     * @param memberId 会员ID
     * @param size 显示的数量
     * @return
     */
    Stream<TopicReplica> getAllForMemberReply(long memberId, int size);
    
    /**
     * 查看会员发布的受欢迎的话题列表,级联加载版块,话题统计
     *
     * @param memberId 会员ID
     * @param size 显示的数量
     * @return
     */
    Stream<TopicReplica> getAllForMemberPopular(long memberId, int size);
    
    /**
     * 查看最近发布的话题,不包括删除的,不包含1号(举报和反馈所在)版块的
     *
     * @param size 显示的数量
     * @return
     */
    Stream<Topic> getRecent(int size);
    
    /**
     * 查看最近发布的话题,不建议前台使用,包含所有版块,所有状态的
     *
     * @param size 显示的数量
     * @return
     */
    Stream<Topic> getRecentIgnoreCondition(int size);
    
    /**
     * 查看指定版块组最近发布的话题,方法将级联加载话题统计
     *
     * @param boardGroupId 版块组(卷)ID
     * @param size 显示的数量
     * @return
     */
    Stream<TopicReplica> getRecent(int boardGroupId, int size);
    
    /**
     * 查看指定版块组(卷)下的精华话题
     *
     * @param boardGroupId 版块组(卷)ID
     * @param size 显示的数量
     * @return
     */
    Stream<Topic> getGoodsForBoardGroup(int boardGroupId, int size);
    
    /**
     * 查看指定版块组(卷)下的最多回复的话题
     *
     * @param boardGroupId 版块组(卷)ID
     * @param size 显示的数量
     * @return
     */
    Stream<Topic> getMaxReplyForBoardGroup(int boardGroupId, int size);
    
    /**
     * 查看回复最多的话题
     *
     * @param size 显示的数量
     * @return
     */
    Stream<Topic> getHot(int size);
    
    /**
     * 按回复时间查看指定的话题
     *
     * @param size 显示的数量
     * @return
     */
    Stream<Topic> getRecentReply(int size);
    
    /**
     * 查看版块的话题列表,最先发布的排在最前面(Topic.entryDateTime ASC)
     *
     * @param boardId 版块ID
     * @param status 话题的状态
     * @return
     */
    Stream<Topic> getAllByBoard(long boardId, ForumEntityStatusEnum status);
    
    /**
     * 最近子栏目发布的文章列表,此方法有别与以下方法 getRecentIgnoreCondition, getRecentRelateContent, getRecent
     *
     * @since 20200427
     * @param size 显示的数量
     * @return
     */
    Stream<Topic> getRecentTermArticle(int size);
    
    /**
     * 查看指定话题相关的话题
     *
     * @param id 话题ID
     * @param size 显示的数量
     * @return
     */
    Stream<TagRelateTopic> getRelateTopic(long id, int size);
    
    /**
     * 查看最近发布的话题,不包括删除的,不包含举报和反馈类型的.方法会级联加载版块,话题统计
     *
     * @param size 显示的数量
     * @return
     */
    List<TopicReplica> getRecentRelateContent(int size);
    
    /**
     * 自参考日期以后版块最近的话题,会级联加载话题统计
     *
     * @param boardId 版块ID
     * @param prevUnixStamp 参考日期
     * @return
     */
    List<TopicReplica> getRecentByUnixStamp(long boardId, int prevUnixStamp);

    /**
     * 自参考日期以后版块最近的话题数量
     *
     * @param boardId 版块ID
     * @param prevUnixStamp 参考日期
     * @return
     */
    long getRecentByUnixStampSize(long boardId, int prevUnixStamp);

    /**
     * [Cacheable]查看指定的话题
     *
     * @param id 话题ID
     * @return
     */
    Optional<Topic> get(long id);
    
    /**
     * 如果话题存在会关联相关对象:统计
     *
     * @param id 话题ID
     * @return
     */
    Optional<TopicReplica> getTopicStats(long id);
    
    /**
     * 查看指定话题, 级联加载版块组(卷), 版块
     *
     * @param id 话题ID
     * @param boardId 版块ID
     * @param boardGroupId 版块组(卷)ID
     * @return
     */
    Optional<TopicReplica> get(long id, long boardId, int boardGroupId);
    
    /**
     * 查看指定话题, 级联加载版块
     *
     * @param id 话题ID
     * @param boardId 版块ID
     * @return
     */
    Optional<TopicReplica> get(long id, long boardId);
    
    /**
     * 如果话题存在会级联加载话题配置
     *
     * @param id 话题ID
     * @return
     */
    Optional<TopicReplica> getTopicConfig(long id);
    
    /**
     * 查看指定的话题,加载话题的内容并且对内容进行解码(若内容中含有图片进行懒加载),加载话题的统计信息 [后台查看话题]
     *
     * @param id 话题ID
     * @param imageIO 图片存储信息
     * @return
     */
    Optional<TopicReplica> getTopicContentAndStats(long id, ImageIOMeta imageIO);
    
    /**
     * 查看指定的话题,加载话题的内容并且对内容进行解码(若内容中含有图片不进行懒加载),加载话题的统计信息
     *
     * @param id 话题ID
     * @param imageIO 图片存储信息
     * @return
     */
    Optional<TopicReplica> getTopicContentAndStatsForRSS(long id, ImageIOMeta imageIO);
    
    /**
     * 查看子栏目中指定的文章内容并且对内容进行解码(若内容中含有图片进行懒加载)
     *
     * @since 20200427
     * @param id 文章ID
     * @param imageIO 图片存储信息
     * @return
     */
    Optional<TopicReplica> getTermArticleContent(long id, ImageIOMeta imageIO);
    
    /**
     * 查看指定的话题,加载话题的内容,加载话题的统计信息(前端话题内容页)
     * 
     * @param id 话题ID
     * @return
     */
    Optional<TopicReplica> getTopicContentAndStats(long id);
    
    /**
     * 查看指定的话题,加载话题的内容(后端为话题新增标签)
     * 
     * @param id 话题ID
     * @return
     */
    Optional<TopicReplica> getTopicContent(long id);
    
    /**
     * 查看栏目中的第一篇文章. 加载话题的内容并且对内容进行解码(若内容中含有图片进行懒加载)
     *
     * @since 20200427
     * @param termId 子栏目ID
     * @param imageIO 图片存储信息
     * @return
     */
    Optional<TopicReplica> getFirstArticleForTerm(long termId, ImageIOMeta imageIO)throws ReplicableException,IllegalArgumentException;
    
    /**
     * 统计版块今天的话题数量
     *
     * @return
     */
    Map<Long, Long> statsBoardTopicesForToday();
    
    /**
     * 统计版块在指定日期的话题数量
     *
     * @param start 开始日期
     * @param finish 结束日期
     * @return Key=版块ID, Value=话题数量
     */
    Map<Long, Long> statsBoardTopicesForDate(LocalDateTime start, LocalDateTime finish);
    
    /**
     * 分组统计指定日期范围内的每日话题数量
     *
     * @param start 开始日期
     * @param finish 结束日期
     * @return Key=YYYY-MM-DD, Value=话题数量
     */
    TreeMap<String, Long> groupTopicesForDate(LocalDateTime start, LocalDateTime finish);
    
    /**
     * 分组统计不同状态的话题数量
     *
     * @return Key=Topic.status, Value=话题数量
     */
    Map<ForumEntityStatusEnum, Long> groupTopicesForStatus();
    
    /**
     * 分组统计不同分类的话题数量
     *
     * @return Key=Topic.topicCategoryName, Value=话题数量
     */
    Map<String, Long> groupTopicesForCategory();
    
    /**
     * 分组统计不同版块的话题数量.版块统计内有此数据
     *
     * @return Key=Topic.boardId, Value=话题数量
     */
    Map<Board, Long> groupTopicesForBoard();
    
    /**
     * 查看子栏目中指定文章上一篇和下一篇文章
     *
     * @since 20200427
     * @param termId 子栏目ID
     * @param articleId 文章ID
     * @return key = PREV|NEXT value = 上一条话题|下一条话题,Key不存在表示不存在对应的话题
     */
    Map<String, Topic> getPrevNextTermArticle(long termId, long articleId);
}